﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Runtime.Serialization;
using System.Text.RegularExpressions;

namespace Toybox.NicoSharp.Seiga
{
	using Utilities;
	using Extensions;

	partial class Manga
	{

		public class JsonThreadResult
		{

			public JsonThread thread;

			public JsonLeaf[] leaves;

			public JsonView_Counter view_counter;

			public JsonChat[] chats;

		}

		[DataContract]
		public class JsonThread
		{
			[DataMember]
			public int resultcode;

			[DataMember]
			public int thread;

			[DataMember]
			public int last_res;

			[DataMember]
			public string ticket;

			[DataMember]
			public int revision;

			[DataMember]
			public int server_time;
		}

		[DataContract]
		public class JsonLeaf
		{
			[DataMember]
			public int thread;

			[DataMember]
			public int leaf;

			[DataMember]
			public int count;
		}

		[DataContract]
		public class JsonView_Counter
		{
			[DataMember]
			public int video;

			[DataMember]
			public string id;
		}

		[DataContract]
		public class JsonChat
		{
			[DataMember]
			public int thread;

			[DataMember]
			public int no;

			[DataMember]
			public int vpos;

			[DataMember]
			public int date;

			[DataMember]
			public string mail;

			[DataMember]
			public string user_id;

			[DataMember]
			public int anonymity;

			[DataMember]
			public int leaf;

			[DataMember]
			public string content;
		}


		[DataContract]
		public class JsonPostKey
		{

			#region [Static]

			public static JsonPostKey GetPostKey(string thread, int block_no, CookieCollection cookies = null)
			{
				cookies = cookies.Coerce();

				Dictionary<string, string> dict = new Dictionary<string, string>();
				dict.Add("thread", thread);
				dict.Add("block_no", block_no.ToString());

				string url = NicoUrls.SeigaTop + "ajax/comment/getpostkey?" + Serializer.AndEqualPairSerializer(dict);
				string json = NicoWebClient.Get(url, cookies);

				return Deserializer.JsonDeserializer<JsonPostKey>(json);
			}

			#endregion [Static]


			#region Public Members

			[DataMember]
			public int success;

			[DataMember]
			public string postkey;

			[DataMember]
			public string user_id;

			[DataMember]
			public int premium;

			#endregion Public Members

		}


		[DataContract]
		public class JsonChatResult
		{
			[DataMember]
			public int thread;

			[DataMember]
			public int status;

			[DataMember]
			public int no;

			[DataMember]
			public int leaf;
		}

		public class JsonCommentClient
		{

			#region [Static]

			public const string VERSION_JQUERY = "20090904";

			public const string REGEX_THREAD = "{\"thread\":(?<inner>{.*?})}";
			public const string REGEX_LEAF = "{\"leaf\":(?<inner>{.*?})}";
			public const string REGEX_VIEW_COUNTER = "{\"view_counter\":(?<inner>{.*?})}";
			public const string REGEX_CHAT = "{\"chat\":(?<inner>{.*?})}";

			public const string REGEX_CHAT_RESULT = "{\"chat_result\":(?<inner>{.*?})}";

			#endregion [Static]


			#region Constructor

			public JsonCommentClient(Manga.Thread thread, CookieCollection cookies)
			{
				this.Thread = thread;
				this.Cookies = cookies;
			}

			#endregion Constructor


			#region Public Members

			public Manga.Thread Thread
			{
				get;
				protected set;
			}

			public CookieCollection Cookies
			{
				get;
				set;
			}

			#endregion Public Members


			#region Public Methods

			public JsonThreadResult GetJsonThread(int res_from = -1000)
			{
				CookieCollection cookies = this.Cookies.Coerce();

				Dictionary<string, string> dict = new Dictionary<string, string>();
				dict.Add("callback", "jQuery");
				dict.Add("thread", this.Thread.id);
				dict.Add("version", VERSION_JQUERY);
				dict.Add("res_from", res_from.ToString());

				string url = this.Thread.url + "api.json/thread?" + Serializer.AndEqualPairSerializer(dict);

				string json = NicoWebClient.Get(url, cookies);

				JsonThreadResult jQuery = new JsonThreadResult();

				// thread
				MatchCollection matches = Regex.Matches(json, REGEX_THREAD);
				if (0 < matches.Count)
					jQuery.thread = Deserializer.JsonDeserializer<JsonThread>(matches[0].Groups["inner"].Value);

				// leaf
				matches = Regex.Matches(json, REGEX_LEAF);
				List<JsonLeaf> leaves = new List<JsonLeaf>();
				foreach (Match match in matches)
					leaves.Add(Deserializer.JsonDeserializer<JsonLeaf>(match.Groups["inner"].Value));
				jQuery.leaves = leaves.ToArray();

				// leaf
				matches = Regex.Matches(json, REGEX_VIEW_COUNTER);
				if (0 < matches.Count)
					jQuery.view_counter = Deserializer.JsonDeserializer<JsonView_Counter>(matches[0].Groups["inner"].Value);

				// leaf
				matches = Regex.Matches(json, REGEX_CHAT);
				List<JsonChat> chats = new List<JsonChat>();
				foreach (Match match in matches)
					chats.Add(Deserializer.JsonDeserializer<JsonChat>(match.Groups["inner"].Value));
				jQuery.chats = chats.ToArray();

				return jQuery;
			}

			public JsonChatResult GetJsonChat(JsonThread jThread, string body, string mail, int leaf, int vpos, int sage = 0)
			{
				if (string.IsNullOrEmpty(body))
					throw new ArgumentNullException("body");

				CookieCollection cookies = this.Cookies.Coerce();
				JsonPostKey key = JsonPostKey.GetPostKey(jThread.thread.ToString(), (jThread.last_res + 1) / 100, cookies);

				Dictionary<string, string> dict = new Dictionary<string, string>();
				dict.Add("callback", "jQuery");
				dict.Add("body", Uri.EscapeUriString(body));
				dict.Add("mail", string.IsNullOrEmpty(mail) ? string.Empty : Uri.EscapeDataString(mail.Replace(' ', '_')).Replace('_', '+'));
				dict.Add("leaf", leaf.ToString());
				dict.Add("vpos", vpos.ToString());
				dict.Add("thread", jThread.thread.ToString());
				dict.Add("ticket", jThread.ticket);
				dict.Add("postkey", key.postkey);
				dict.Add("user_id", key.user_id);
				dict.Add("sage", sage.ToString());
				dict.Add("premium", key.premium.ToString());

				string url = this.Thread.url + "api.json/chat?" + Serializer.AndEqualPairSerializer(dict);
				string json = NicoWebClient.Get(url, cookies);

				// thread
				JsonChatResult result;
				Match match = Regex.Match(json, REGEX_CHAT_RESULT);
				result = match.Success ? Deserializer.JsonDeserializer<JsonChatResult>(match.Groups["inner"].Value) : null;

				return result;
			}

			#endregion Public Methods

		}
	}
}